بیاموزید چگونه از هوکهای سفارشی ریاکت برای استخراج و استفاده مجدد منطق کامپوننت بهره ببرید و قابلیت نگهداری، تستپذیری و معماری کلی برنامه را بهبود بخشید.
هوکهای سفارشی ریاکت: استخراج منطق کامپوننت برای استفاده مجدد
هوکهای ریاکت روش نوشتن کامپوننتهای ریاکت را متحول کردهاند و راهی زیباتر و کارآمدتر برای مدیریت وضعیت و اثرات جانبی ارائه میدهند. در میان هوکهای مختلف موجود، هوکهای سفارشی به عنوان ابزاری قدرتمند برای استخراج و استفاده مجدد منطق کامپوننت برجسته میشوند. این مقاله راهنمایی جامع برای درک و پیادهسازی هوکهای سفارشی ریاکت ارائه میدهد و شما را قادر میسازد برنامههایی با قابلیت نگهداری، تستپذیری و مقیاسپذیری بیشتر بسازید.
هوکهای سفارشی ریاکت چیستند؟
در اصل، یک هوک سفارشی یک تابع جاوااسکریپت است که نام آن با "use" شروع میشود و میتواند هوکهای دیگر را فراخوانی کند. این به شما امکان میدهد منطق کامپوننت را در توابع قابل استفاده مجدد استخراج کنید، در نتیجه تکرار کد را از بین میبرد و ساختار کامپوننت تمیزتری را ترویج میدهد. برخلاف کامپوننتهای معمولی ریاکت، هوکهای سفارشی هیچ رابط کاربری را رندر نمیکنند؛ آنها صرفاً منطق را کپسوله میکنند.
به آنها به عنوان توابع قابل استفاده مجدد فکر کنید که میتوانند به ویژگیهای وضعیت و چرخه حیات ریاکت دسترسی داشته باشند. آنها راهی فوقالعاده برای اشتراکگذاری منطق حالتدار بین کامپوننتهای مختلف بدون توسل به کامپوننتهای سطح بالاتر (higher-order components) یا propهای رندر (render props) هستند که اغلب میتوانند منجر به کدی شوند که خواندن و نگهداری آن دشوار است.
چرا از هوکهای سفارشی استفاده کنیم؟
مزایای استفاده از هوکهای سفارشی متعدد است:
- قابلیت استفاده مجدد: منطق را یک بار بنویسید و آن را در چندین کامپوننت استفاده کنید. این به طور قابل توجهی تکرار کد را کاهش میدهد و برنامه شما را قابل نگهداریتر میکند.
- سازماندهی بهتر کد: استخراج منطق پیچیده به هوکهای سفارشی، کامپوننتهای شما را تمیز میکند و خواندن و درک آنها را آسانتر میسازد. کامپوننتها بر مسئولیتهای اصلی رندر خود تمرکز میکنند.
- قابلیت تست پیشرفته: هوکهای سفارشی به راحتی در حالت جداگانه قابل تست هستند. شما میتوانید منطق هوک را بدون رندر کردن یک کامپوننت تست کنید، که منجر به تستهای قویتر و قابل اطمینانتر میشود.
- قابلیت نگهداری افزایش یافته: هنگامی که منطق تغییر میکند، شما فقط باید آن را در یک مکان - هوک سفارشی - به جای هر کامپوننتی که از آن استفاده میکند، بهروزرسانی کنید.
- کاهش کد تکراری (Boilerplate): هوکهای سفارشی میتوانند الگوهای رایج و وظایف تکراری را کپسوله کنند و مقدار کد تکراری را که باید در کامپوننتهای خود بنویسید، کاهش دهند.
ایجاد اولین هوک سفارشی
بیایید ایجاد و استفاده از یک هوک سفارشی را با یک مثال عملی نشان دهیم: دریافت داده از یک API.
مثال: useFetch
- یک هوک دریافت داده
تصور کنید که اغلب نیاز به دریافت داده از APIهای مختلف در برنامه ریاکت خود دارید. به جای تکرار منطق دریافت در هر کامپوننت، میتوانید یک هوک useFetch
ایجاد کنید.
import { useState, useEffect } from 'react';
function useFetch(url) {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
const abortController = new AbortController();
const signal = abortController.signal;
const fetchData = async () => {
setLoading(true);
try {
const response = await fetch(url, { signal: signal });
if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`);
}
const json = await response.json();
setData(json);
setError(null); // پاک کردن هرگونه خطای قبلی
} catch (error) {
if (error.name === 'AbortError') {
console.log('Fetch aborted');
} else {
setError(error);
}
setData(null); // پاک کردن هرگونه داده قبلی
} finally {
setLoading(false);
}
};
fetchData();
return () => {
abortController.abort(); // تابع پاکسازی برای لغو دریافت در هنگام جداسازی یا تغییر URL
};
}, [url]); // اجرای مجدد اثر زمانی که URL تغییر میکند
return { data, loading, error };
}
export default useFetch;
توضیح:
- متغیرهای وضعیت: هوک از
useState
برای مدیریت وضعیت داده، بارگذاری و خطا استفاده میکند. - useEffect: هوک
useEffect
دریافت داده را هنگام تغییر propurl
انجام میدهد. - مدیریت خطا: هوک شامل مدیریت خطا برای گرفتن خطاهای احتمالی در طول عملیات دریافت است. کد وضعیت بررسی میشود تا از موفقیتآمیز بودن پاسخ اطمینان حاصل شود.
- وضعیت بارگذاری: وضعیت
loading
برای نشان دادن اینکه آیا داده هنوز در حال دریافت است، استفاده میشود. - AbortController: از API AbortController برای لغو درخواست دریافت در صورت جداسازی کامپوننت یا تغییر URL استفاده میکند. این از نشت حافظه جلوگیری میکند.
- مقدار بازگشتی: هوک یک شی شامل وضعیتهای
data
،loading
وerror
را برمیگرداند.
استفاده از هوک useFetch
در یک کامپوننت
حالا بیایید ببینیم چگونه میتوان از این هوک سفارشی در یک کامپوننت ریاکت استفاده کرد:
import React from 'react';
import useFetch from './useFetch';
function UserList() {
const { data: users, loading, error } = useFetch('https://jsonplaceholder.typicode.com/users');
if (loading) return <p>در حال بارگذاری کاربران...</p>;
if (error) return <p>خطا: {error.message}</p>;
if (!users) return <p>کاربری یافت نشد.</p>;
return (
<ul>
{users.map(user => (
<li key={user.id}>{user.name} ({user.email})</li>
))}
</ul>
);
}
export default UserList;
توضیح:
- کامپوننت هوک
useFetch
را وارد میکند. - آن هوک را با URL API فراخوانی میکند.
- شی بازگشتی را بازسازی میکند تا به وضعیتهای
data
(که بهusers
تغییر نام داده شده)،loading
وerror
دسترسی پیدا کند. - محتوای متفاوتی را بر اساس وضعیتهای
loading
وerror
به طور مشروط رندر میکند. - اگر دادهها در دسترس باشند، لیستی از کاربران را نمایش میدهد.
الگوهای پیشرفته هوک سفارشی
فراتر از دریافت دادههای ساده، هوکهای سفارشی میتوانند برای کپسوله کردن منطق پیچیدهتر استفاده شوند. در اینجا چند الگوی پیشرفته آورده شده است:
۱. مدیریت وضعیت با useReducer
برای سناریوهای پیچیدهتر مدیریت وضعیت، میتوانید هوکهای سفارشی را با useReducer
ترکیب کنید. این به شما امکان میدهد تا انتقالهای وضعیت را به شیوهای قابل پیشبینیتر و سازمانیافتهتر مدیریت کنید.
import { useReducer } from 'react';
const initialState = { count: 0 };
function reducer(state, action) {
switch (action.type) {
case 'increment':
return { count: state.count + 1 };
case 'decrement':
return { count: state.count - 1 };
default:
throw new Error();
}
}
function useCounter() {
const [state, dispatch] = useReducer(reducer, initialState);
const increment = () => dispatch({ type: 'increment' });
const decrement = () => dispatch({ type: 'decrement' });
return { count: state.count, increment, decrement };
}
export default useCounter;
استفاده:
import React from 'react';
import useCounter from './useCounter';
function Counter() {
const { count, increment, decrement } = useCounter();
return (
<div>
<p>تعداد: {count}</p>
<button onClick={increment}>افزایش</button>
<button onClick={decrement}>کاهش</button>
</div>
);
}
export default Counter;
۲. ادغام Context با useContext
هوکهای سفارشی همچنین میتوانند برای سادهسازی دسترسی به Context ریاکت استفاده شوند. به جای استفاده مستقیم از useContext
در کامپوننتهای خود، میتوانید یک هوک سفارشی ایجاد کنید که منطق دسترسی به Context را کپسوله کند.
import { useContext } from 'react';
import { ThemeContext } from './ThemeContext'; // فرض میشود ThemeContext دارید
function useTheme() {
return useContext(ThemeContext);
}
export default useTheme;
استفاده:
import React from 'react';
import useTheme from './useTheme';
function MyComponent() {
const { theme, toggleTheme } = useTheme();
return (
<div style={{ backgroundColor: theme.background, color: theme.color }}>
<p>این کامپوننت من است.</p>
<button onClick={toggleTheme}>تغییر تم</button>
</div>
);
}
export default MyComponent;
۳. Debouncing و Throttling
Debouncing و Throttling تکنیکهایی هستند که برای کنترل نرخ اجرای یک تابع استفاده میشوند. هوکهای سفارشی میتوانند برای کپسوله کردن این منطق استفاده شوند و اعمال این تکنیکها را بر روی پردازشگرهای رویداد آسان کنند.
import { useState, useEffect, useRef } from 'react';
function useDebounce(value, delay) {
const [debouncedValue, setDebouncedValue] = useState(value);
useEffect(() => {
const handler = setTimeout(() => {
setDebouncedValue(value);
}, delay);
return () => {
clearTimeout(handler);
};
}, [value, delay]);
return debouncedValue;
}
export default useDebounce;
استفاده:
import React, { useState } from 'react';
import useDebounce from './useDebounce';
function SearchInput() {
const [searchValue, setSearchValue] = useState('');
const debouncedSearchValue = useDebounce(searchValue, 500); // Debounce برای ۵۰۰ میلیثانیه
useEffect(() => {
// انجام جستجو با debouncedSearchValue
console.log('در حال جستجو برای:', debouncedSearchValue);
// console.log را با منطق جستجوی واقعی خود جایگزین کنید
}, [debouncedSearchValue]);
const handleChange = (event) => {
setSearchValue(event.target.value);
};
return (
<input
type="text"
value={searchValue}
onChange={handleChange}
placeholder="جستجو..."
/>
);
}
export default SearchInput;
بهترین شیوهها برای نوشتن هوکهای سفارشی
برای اطمینان از اینکه هوکهای سفارشی شما مؤثر و قابل نگهداری هستند، این بهترین شیوهها را دنبال کنید:
- با "use" شروع کنید: همیشه نام هوکهای سفارشی خود را با پیشوند "use" قرار دهید. این قرارداد به ریاکت نشان میدهد که تابع از قوانین هوکها پیروی میکند و میتواند در کامپوننتهای تابعی استفاده شود.
- متمرکز نگه دارید: هر هوک سفارشی باید یک هدف مشخص و واضح داشته باشد. از ایجاد هوکهای بیش از حد پیچیده که مسئولیتهای زیادی را بر عهده دارند، خودداری کنید.
- مقادیر مفید را برگردانید: یک شی حاوی تمام مقادیر و توابعی که کامپوننت استفاده کننده از هوک به آنها نیاز دارد، برگردانید. این باعث انعطافپذیرتر و قابل استفاده مجدد شدن هوک میشود.
- خطاها را به خوبی مدیریت کنید: مدیریت خطا را در هوکهای سفارشی خود بگنجانید تا از رفتار غیرمنتظره در کامپوننتهای خود جلوگیری کنید.
- پاکسازی را در نظر بگیرید: از تابع پاکسازی در
useEffect
برای جلوگیری از نشت حافظه و اطمینان از مدیریت صحیح منابع استفاده کنید. این امر به ویژه هنگام کار با اشتراکها، تایمرها یا شنوندگان رویداد مهم است. - تست بنویسید: هوکهای سفارشی خود را به طور کامل در حالت جداگانه تست کنید تا اطمینان حاصل کنید که مطابق انتظار عمل میکنند.
- هوکهای خود را مستند کنید: مستندات روشنی را برای هوکهای سفارشی خود ارائه دهید، هدف، نحوه استفاده و هرگونه محدودیت احتمالی را توضیح دهید.
ملاحظات جهانی
هنگام توسعه برنامهها برای مخاطبان جهانی، موارد زیر را در نظر داشته باشید:
- بینالمللیسازی (i18n) و محلیسازی (l10n): اگر هوک سفارشی شما با متن یا دادههای قابل مشاهده برای کاربر سروکار دارد، نحوه بینالمللیسازی و محلیسازی آن برای زبانها و مناطق مختلف را در نظر بگیرید. این ممکن است شامل استفاده از کتابخانهای مانند
react-intl
یاi18next
باشد. - قالببندی تاریخ و زمان: به قالبهای مختلف تاریخ و زمان که در سراسر جهان استفاده میشوند، توجه داشته باشید. از توابع یا کتابخانههای قالببندی مناسب برای اطمینان از نمایش صحیح تاریخ و زمان برای هر کاربر استفاده کنید.
- قالببندی ارز: به طور مشابه، قالببندی ارز را به طور مناسب برای مناطق مختلف مدیریت کنید.
- قابلیت دسترسی (a11y): اطمینان حاصل کنید که هوکهای سفارشی شما به طور منفی بر قابلیت دسترسی برنامه شما تأثیر نمیگذارند. کاربرانی را که دارای معلولیت هستند در نظر بگیرید و بهترین شیوههای دسترسی را دنبال کنید.
- عملکرد: از پیامدهای احتمالی عملکرد هوکهای سفارشی خود، به ویژه هنگام کار با منطق پیچیده یا مجموعه دادههای بزرگ، آگاه باشید. کد خود را بهینه کنید تا اطمینان حاصل کنید که برای کاربران در مکانهای مختلف با سرعتهای مختلف شبکه عملکرد خوبی دارد.
مثال: قالببندی تاریخ بینالمللی با یک هوک سفارشی
import { useState, useEffect } from 'react';
import { DateTimeFormat } from 'intl';
function useFormattedDate(date, locale) {
const [formattedDate, setFormattedDate] = useState('');
useEffect(() => {
try {
const formatter = new DateTimeFormat(locale, {
year: 'numeric',
month: 'long',
day: 'numeric',
});
setFormattedDate(formatter.format(date));
} catch (error) {
console.error('خطا در قالببندی تاریخ:', error);
setFormattedDate('تاریخ نامعتبر');
}
}, [date, locale]);
return formattedDate;
}
export default useFormattedDate;
استفاده:
import React from 'react';
import useFormattedDate from './useFormattedDate';
function MyComponent() {
const today = new Date();
const enDate = useFormattedDate(today, 'en-US');
const frDate = useFormattedDate(today, 'fr-FR');
const deDate = useFormattedDate(today, 'de-DE');
return (
<div>
<p>تاریخ آمریکا: {enDate}</p>
<p>تاریخ فرانسه: {frDate}</p>
<p>تاریخ آلمان: {deDate}</p>
</div>
);
}
export default MyComponent;
نتیجهگیری
هوکهای سفارشی ریاکت مکانیزم قدرتمندی برای استخراج و استفاده مجدد منطق کامپوننت هستند. با بهرهگیری از هوکهای سفارشی، میتوانید کدی تمیزتر، قابل نگهداریتر و قابل تستتر بنویسید. با تسلط بیشتر بر ریاکت، تسلط بر هوکهای سفارشی به طور قابل توجهی توانایی شما در ساخت برنامههای پیچیده و مقیاسپذیر را بهبود میبخشد. به یاد داشته باشید که بهترین شیوهها را دنبال کنید و عوامل جهانی را هنگام توسعه هوکهای سفارشی در نظر بگیرید تا اطمینان حاصل کنید که برای مخاطبان متنوع مؤثر و قابل دسترسی هستند. قدرت هوکهای سفارشی را در آغوش بگیرید و مهارتهای توسعه ریاکت خود را ارتقا دهید!